﻿using System.Collections;
using System.Text;
using Basic.FormCollect;
using Basic.FormModel.Column;
using Basic.FormRemoteModel;
using Basic.FormRemoteModel.Column.Model;
using Basic.UserFormService.Interface;
using Basic.UserFormService.Model;
using WeDonekRpc.CacheClient.Interface;
using WeDonekRpc.Helper;

namespace Basic.UserFormService.lmpl
{
    internal class UserFormFormulaService : IUserFormFormulaService
    {
        private readonly ITableColumnCollect _TableColumn;
        private readonly ICacheController _Cache;
        private readonly ICustomTableCollect _Table;
        public UserFormFormulaService ( ICacheController cache,
            ICustomTableCollect table,
            ITableColumnCollect column )
        {
            this._Table = table;
            this._Cache = cache;
            this._TableColumn = column;
        }
        private ColumnStruct[] _columns;
        public FormFormulaStruct Get ( long formId )
        {
            string key = string.Concat("FormStuct_", formId);
            if ( !this._Cache.TryGet(key, out FormFormulaStruct dto) )
            {
                dto = this._Get(formId);
                _ = this._Cache.Set(key, dto, DateTime.Now.AddDays(1));
            }
            return dto;
        }
        private List<long> _dicId = null;
        private List<long> _treeDicId = null;
        private Dictionary<long, Dictionary<string, string>> _items;
        private FormFormulaStruct _Get ( long formId )
        {
            FormFormulaStruct body = new FormFormulaStruct
            {
                FormId = formId,
            };
            body.TableType = this._Table.GetsByFormId(formId, a => new
            {
                a.Id,
                a.TableType
            }).ToDictionary(a => a.Id, a => a.TableType);
            this._columns = this._TableColumn.GetsByFormId<ColumnStruct>(formId);
            if ( this._columns.IsNull() )
            {
                return body;
            }
            this._dicId = new List<long>();
            this._treeDicId = new List<long>();
            this._items = new Dictionary<long, Dictionary<string, string>>();
            body.Formula = this._columns.Convert(a => a.Formula != null, a =>
            {
                ColFormulaVar[] vars = this._InitFormula(a.Formula, out string formula);
                return new ColFormula
                {
                    Formula = formula,
                    Name = a.ColName,
                    VarCol = vars,
                    TableId = a.TableId,
                    DataType = a.DataType,
                    ColId = a.Id,
                };
            });
            body.DicId = this._dicId.Distinct().ToArray();
            body.TreeDicId = this._treeDicId.Distinct().ToArray();
            this._dicId.Clear();
            this._treeDicId.Clear();
            body.StateControl = new Dictionary<long, FormStateControl>();
            body.DefState = new Dictionary<long, FormStateControl>();
            body.StateFormula = this._columns.Convert(a => a.StateFormula != null, a =>
            {
                body.StateControl.Add(a.Id, a.StateControl);
                body.DefState.Add(a.Id, a.DefState);
                ColFormulaVar[] vars = this._InitFormula(a.StateFormula, out string formula);
                return new ColFormula
                {
                    Formula = formula,
                    Name = a.ColName,
                    VarCol = vars,
                    TableId = a.TableId,
                    DataType = a.DataType,
                    ColId = a.Id,
                };
            });
            body.StateDicId = this._dicId.Distinct().ToArray();
            body.TreeStateDicId = this._treeDicId.Distinct().ToArray();
            body.Items = this._items;
            return body;
        }
        private ColFormulaVar[] _InitFormula ( ColumnFormula obj, out string formula )
        {
            if ( obj.VarCol.IsNull() )
            {
                formula = obj.Formula;
                return null;
            }
            StringBuilder str = new StringBuilder();
            string[] rows = obj.Formula.Split('\n');
            Dictionary<long, ColFormulaVar> dic = new Dictionary<long, ColFormulaVar>();
            int index = 0;
            rows.ForEach(( row, i ) =>
            {
                FormulaVar[] vars = obj.VarCol.Where(c => c.From.Line == i).OrderBy(c => c.From.Ch).ToArray();
                if ( !vars.IsNull() )
                {
                    int begin = 0;
                    vars.ForEach(c =>
                    {
                        if ( !dic.TryGetValue(c.ColId, out ColFormulaVar var) )
                        {
                            ColumnStruct col = this._columns.Find(a => a.Id == c.ColId);
                            var = new ColFormulaVar
                            {
                                ColId = c.ColId,
                                TableId = c.TableId,
                                Name = col.ColName,
                                FuncType = col.FuncType,
                                DataType = col.DataType,
                                Key = PublicDataDic.Letter[index % 26] + ( index < 26 ? string.Empty : ( index / 26 ).ToString() )
                            };
                            if ( col.ColType == ControlType.Customize && ( col.FuncType == DataFuncType.树形字典 || col.FuncType == DataFuncType.字典项 ) )
                            {
                                Dictionary<string, object> dic = col.ControlSet.Json<Dictionary<string, object>>();
                                if ( dic.TryGetValue("dicId", out object val) )
                                {
                                    var.DicId = Convert.ToInt64(val);
                                    if ( col.FuncType == DataFuncType.树形字典 )
                                    {
                                        this._treeDicId.Add(var.DicId.Value);
                                    }
                                    else
                                    {
                                        this._dicId.Add(var.DicId.Value);
                                    }
                                }
                            }
                            else if ( col.ColType == ControlType.Select || col.ColType == ControlType.Checkbox || col.ColType == ControlType.Radio )
                            {
                                if ( !this._items.ContainsKey(col.Id) )
                                {
                                    Dictionary<string, object> dic = col.ControlSet.Json<Dictionary<string, object>>();
                                    if ( dic.TryGetValue("items", out object obj) )
                                    {
                                        IList list = obj as IList;
                                        Dictionary<string, string> items = new Dictionary<string, string>();
                                        foreach ( IDictionary<string, object> i in list )
                                        {
                                            object k = i["value"];
                                            items.Add(Convert.ToString(i["text"]), k == null ? null : Convert.ToString(k));
                                        }
                                        this._items.Add(c.ColId, items);
                                    }
                                }
                            }
                            index++;
                            dic.Add(c.ColId, var);
                        }
                        int t = c.From.Ch;
                        if ( t != 0 )
                        {
                            int tlen = t - begin;
                            _ = str.Append(row.Substring(begin, tlen));
                            begin += tlen;
                        }
                        int len = c.To.Ch - c.From.Ch;
                        _ = str.Append(var.Key);
                        begin += len;
                    });
                    if ( begin != row.Length )
                    {
                        _ = str.Append(row.Substring(begin));
                    }
                }
            });
            formula = str.ToString();
            return dic.Values.ToArray();
        }
    }
}
